/**
 * 采用ES Module 和 Top Await 语法，请务必在Node 14.8环境下运行。并且在Windows下，10.2 ~ 14.5 版本会有终端卡死问题，在14.6中的libuv 1.38.1已经得到修复。
 * 老师，不是我坑您，这个语法确实用的很舒服！
 * 后续我会开源一个自己写的windows下的nvm，比nvm-windows好用
 */

// 以下是导入依赖插件
import readline from 'readline';
import { promisify } from 'util';
import ejs from 'ejs';
import path from 'path';
import fse from 'fs-extra';
import inquirer from 'inquirer';
import dirinfo from './dirinfo.js';
// 这是一个自定义的PWA插件
import pwaHandler from './pwa-plugin/index.mjs';

const { __dirname } = dirinfo;
const { writeFileSync, emptyDirSync, ensureDirSync } = fse;
const { prompt } = inquirer;
const { renderFile } = ejs;

const distDir = path.resolve(__dirname, 'dist'); // 设置目标代码位置

// 对于简单的问答，可以直接使用readline模块。先创建一个readline接口，绑定stdio
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
// 改写promisify方法，使得question函数成为一个promise
rl.question[promisify.custom] = (query) => {
  return new Promise((resolve) => {
    rl.question(query, resolve);
  });
};
const title =
  (await promisify(rl.question)('Title: (default: Task1)')) || 'Task1'; // 拿到用户输入的title
const html = await renderFile(
  path.resolve(__dirname, './template/index.html'),
  {
    title,
  }
); // 通过ejs渲染html
const baseInfo = {
  title,
  html,
};
rl.close();

// 自定义了一个plugin管理器
const [listExtra, registerHandler, handle] = (() => {
  const extraFunctionsMap = new Map();
  return [
    () => [...extraFunctionsMap.keys()],
    (name, handler) => {
      extraFunctionsMap.set(name, handler);
    },
    (name) => extraFunctionsMap.get(name)(),
  ];
})();

registerHandler('PWA', () =>
  pwaHandler({
    distDir,
    payload: baseInfo, // 将基础信息作为对象传入，以便修改其中的内容
  })
);

// 复杂场景我们直接使用inquirer.js
const { extra } = await prompt([
  {
    type: 'checkbox',
    message: 'Enable Extra Function',
    name: 'extra',
    choices: listExtra().map((name) => ({ name })),
  },
]);
emptyDirSync(distDir);
ensureDirSync(distDir);
for (const name of extra) {
  await handle(name);
}
writeFileSync(path.resolve(distDir, 'index.html'), baseInfo.html);
